/*
 * $Id$
 *
 * Copyright ( c ) 2014 XuNuo Corporation. All Rights Reserved.
 *
 * This software is the confidential and proprietary information of XuNuo
 * Corporation ("Confidential Information").  You shall not disclose such
 * Confidential Information and shall use it only in accordance with the terms
 * of the license agreement you entered into with XuNuo Corporation or a XuNuo
 * authorized reseller (the "License Agreement"). XuNuo may make changes to the
 * Confidential Information from time to time. Such Confidential Information may
 * contain errors.
 *
 * EXCEPT AS EXPLICITLY SET FORTH IN THE LICENSE AGREEMENT, XuNuo DISCLAIMS ALL
 * WARRANTIES, COVENANTS, REPRESENTATIONS, INDEMNITIES, AND GUARANTEES WITH
 * RESPECT TO SOFTWARE AND DOCUMENTATION, WHETHER EXPRESS OR IMPLIED, WRITTEN OR
 * ORAL, STATUTORY OR OTHERWISE INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A
 * PARTICULAR PURPOSE. XuNuo DOES NOT WARRANT THAT END USER'S USE OF THE
 * SOFTWARE WILL BE UNINTERRUPTED, ERROR FREE OR SECURE.
 *
 * XuNuo SHALL NOT BE LIABLE TO END USER, OR ANY OTHER PERSON, CORPORATION OR
 * ENTITY FOR INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL
 * DAMAGES, OR DAMAGES FOR LOSS OF PROFITS, REVENUE, DATA OR USE, WHETHER IN AN
 * ACTION IN CONTRACT, TORT OR OTHERWISE, EVEN IF XuNuo HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES. XuNuo' TOTAL LIABILITY TO END USER SHALL NOT
 * EXCEED THE AMOUNTS PAID FOR THE XuNuo SOFTWARE BY END USER DURING THE PRIOR
 * TWELVE (12) MONTHS FROM THE DATE IN WHICH THE CLAIM AROSE.  BECAUSE SOME
 * STATES OR JURISDICTIONS DO NOT ALLOW LIMITATION OR EXCLUSION OF CONSEQUENTIAL
 * OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO END USER.
 *
 * Copyright version 2.0
 */
package com.th.supcom.pds.impl.service.internal.chargedpresc.command;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.th.supcom.pds.domain.pojo.PdsPrescDispenseWindow;
import com.th.supcom.pds.domain.pojo.PhamWindowConfig;
import com.th.supcom.pds.domain.vo.PdsSupplyDetailVO;
import com.th.supcom.pds.impl.common.enums.PdsConfigEnableEnum;
import com.th.supcom.pds.impl.common.enums.PrescSupplyDrugState;
import com.th.supcom.pds.impl.common.enums.PutDrugMode;
import com.th.supcom.pds.impl.common.enums.WindowServerType;
import com.th.supcom.pds.impl.service.internal.chargedpresc.AbstractCommand;
import com.th.supcom.pds.impl.service.internal.chargedpresc.ChargedPrescriptionContext;

/**
 * 分配窗口
 * 
 * @author 杨冲
 */
public class WindowDistributeCommand extends AbstractCommand implements Command
{
    /** 日志记录器. */
    private static final Logger s_LOGGER = LoggerFactory.getLogger (WindowDistributeCommand.class);
    Map <String, Object>map=null;
    @Override
    public boolean execute (Context context) throws Exception
    {
        if (s_LOGGER.isInfoEnabled ())
        {
            s_LOGGER.info ("准备执行分配窗口服务，参数信息：{}", context);
        }
        ChargedPrescriptionContext chargedPrescriptionContext = (ChargedPrescriptionContext) context;
        map=chargedPrescriptionContext.getMap ();
        String dispensaryCode =(String)map.get ("dispensaryCode");
        List <PdsSupplyDetailVO> pdsPrescDetailCombines = chargedPrescriptionContext.getPdsSupplyDetails ();
        // 只能分配当前登陆科室对应的明细
        List <PdsSupplyDetailVO> prescDetaillist = new ArrayList <PdsSupplyDetailVO> ();
        for (PdsSupplyDetailVO pdsPrescDetailCombine : pdsPrescDetailCombines)
        {
            if (dispensaryCode.equals (pdsPrescDetailCombine.getPerformedBy()))
            {
                prescDetaillist.add (pdsPrescDetailCombine);
            }
        }
        if (prescDetaillist.isEmpty ())
        {
            s_LOGGER.error ("窗口分配时处方明细为空");
            return false;
        }
        map.put ("prescDetails", prescDetaillist);
        // 根据处方类别来更新处方窗口
        updateWindowNo (prescDetaillist);
        if (s_LOGGER.isInfoEnabled ())
        {
            s_LOGGER.info ("分配窗口结束");
        }
        return false;
    }


    /**
     * 分配窗口
     * 
     * @param pdsPrescDetailCombines
     */
    private void updateWindowNo (List <PdsSupplyDetailVO> pdsSupplyDetailVOs)
    {
        // 获取窗口摆药类型
        String windowServerType = getWindowTypeByList (pdsSupplyDetailVOs);
        String deptCode = pdsSupplyDetailVOs.get (0).getPerformedBy();
        Integer prescClassfication=pdsSupplyDetailVOs.get (0).getPrescClassfication ();
        // 获取符合条件的窗口
        List <PhamWindowConfig> phamWindowConfigs = getAvailableWindow (windowServerType, deptCode,prescClassfication);
        if (phamWindowConfigs.isEmpty ())
        {
            s_LOGGER.error ("没有符合要求的窗口");
            return;
        }
        // 查询窗口排队情况
        Map <String, Object> windowMap = new HashMap <String, Object> ();
        windowMap.put ("performedBy", deptCode);
        windowMap.put ("prescSupplyDrugState", PrescSupplyDrugState.Undispensed.getEnumCode ());
        windowMap.put ("list", phamWindowConfigs);
        List <PdsPrescDispenseWindow> windows =getPdsSupplyProService ().findPdsPrescWindowByMap (windowMap);
        // 分配窗口号
        Long windowNo = getWindow (windows, phamWindowConfigs);
        //得到分配窗口号的名称
        String windowName=getPhamWindowConfigService ().getPhamWindowConfigById (windowNo).getWindowName ();
        map.put ("windowName", windowName);
        map.put ("windowId", windowNo);
        // 更新处方过程窗口
        updatePrescProWindow(pdsSupplyDetailVOs, windowNo);
    }

    private void updatePrescProWindow (List <PdsSupplyDetailVO> pdsPrescDetailCombines, Long windowNo)
    {
        Map<String,Object>map=new HashMap<String,Object>();
        map.put ("windId", windowNo);
        map.put ("list", pdsPrescDetailCombines);
        map.put ("dispensaryCode", pdsPrescDetailCombines.get (0).getPerformedBy ());
        this.getPdsSupplyProService ().modifyBatchSupplyWindow (map);
    }

    /**
     * 获取分配得到的窗口号
     * 
     * @param windows
     * @return
     */
    private Long getWindow (List <PdsPrescDispenseWindow> windows, List <PhamWindowConfig> phamWindowConfigs)
    {
        // 如果phamWindowConfigs中有并且windows中没有，则表示该窗口的排队人数为0;
        Set <Long> set = new HashSet <Long> ();
        int min = Integer.MAX_VALUE;
        Long windowNo = 0L;
        for (PdsPrescDispenseWindow window : windows)
        {
            if (min > window.getWaitCount ())
            {
                min = window.getWaitCount ();
                windowNo = window.getWindowNo ();
                set.add (window.getWindowNo ());
            }
        }

        for (PhamWindowConfig phamWindowConfig : phamWindowConfigs)
        {
            if (!set.contains (phamWindowConfig.getPhamWindowConfigId ()))
            {
                return phamWindowConfig.getPhamWindowConfigId ();
            }
        }

        return windowNo;
    }

    /**
     * 根据处方供药科室获取窗口摆药类型
     * 
     * @param pdsPrescDetailCombines
     * @return
     */
    private String getWindowTypeByList (List <PdsSupplyDetailVO> pdsPrescDetailCombines)
    {
        if (null == pdsPrescDetailCombines)
        {
            return null;
        }
        Set <String> set = new HashSet <String> ();
        for (PdsSupplyDetailVO pdsPrescDetailPham : pdsPrescDetailCombines)
        {
            if (!set.contains (pdsPrescDetailPham.getPutDrugMode ()))
            {
                set.add (pdsPrescDetailPham.getPutDrugMode ());
            }
        }

        return getWindowType (set);

    }

    /**
     * 获取服务窗口类型
     * 
     * @param set
     * @return
     */
    private String getWindowType (Set <String> set)
    {
        if (set.isEmpty ())
        {
            return null;
        }

        if (set.size () > 1)
        {
            return WindowServerType.Mix.getEnumCode ();
        }

        if (set.contains (PutDrugMode.Manual.getEnumCode ()))
        {
            return WindowServerType.Manual.getEnumCode ();
        }

        if (set.contains (PutDrugMode.Mechine.getEnumCode ()))
        {
            return WindowServerType.Mechine.getEnumCode ();
        }

        return null;
    }

    /**
     * 根据服务窗口类型和执行科室获取可用的窗口
     * 
     * @return
     */
    private List <PhamWindowConfig> getAvailableWindow (String windowServerType, String deptCode, Integer prescType)
    {
        PhamWindowConfig phamWindowConfig = new PhamWindowConfig ();
        phamWindowConfig.setDeptCode (deptCode);
        phamWindowConfig.setOpenFlag (PdsConfigEnableEnum.Enable.getCode ());
        phamWindowConfig.setServiceType (windowServerType);
        phamWindowConfig.setPrescType (prescType);
        return this.getPhamWindowConfigService ().findPhamWindowConfigByExample (phamWindowConfig);
    }

}
